Vertiefende Betrachtung der Merkmale¶

Laden¶

In [1]:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.dates as mdates
In [2]:
df = pd.read_csv('df_PreiseStationenAngepasst.csv')
df = df.drop(['Unnamed: 0', 'Unnamed: 0.1'], axis=1)

Ausschließen der Ausreißer

In [3]:
# Quelle: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.quantile.html
def remove_outliers_iqr(df, column):
    Q1 = df[column].quantile(0.25)
    Q3 = df[column].quantile(0.75)
    IQR = Q3 - Q1
    lower = Q1 - 1.5 * IQR
    upper = Q3 + 1.5 * IQR
    return df[(df[column] >= lower) & (df[column] <= upper)]

df_clean = df.copy()
for col in ['e5', 'e10', 'diesel']:
    df_clean = remove_outliers_iqr(df_clean, col)

print(f"Ursprüngliche Form: {df.shape}")
print(f"Bereinigte Form:   {df_clean.shape}")
df = df_clean
Ursprüngliche Form: (73589, 22)
Bereinigte Form:   (73096, 22)
In [4]:
df.info()
<class 'pandas.core.frame.DataFrame'>
Index: 73096 entries, 0 to 73588
Data columns (total 22 columns):
 #   Column             Non-Null Count  Dtype  
---  ------             --------------  -----  
 0   station_uuid       73096 non-null  object 
 1   hour               73096 non-null  object 
 2   diesel             73096 non-null  float64
 3   e5                 73096 non-null  float64
 4   e10                73096 non-null  float64
 5   dieselchange       73096 non-null  float64
 6   e5change           73096 non-null  float64
 7   e10change          73096 non-null  float64
 8   brand              67604 non-null  object 
 9   city               73096 non-null  object 
 10  street             73096 non-null  object 
 11  house_number       73096 non-null  int64  
 12  name               73096 non-null  object 
 13  post_code          73096 non-null  int64  
 14  latitude           73096 non-null  float64
 15  longitude          73096 non-null  float64
 16  first_active       73096 non-null  object 
 17  openingtimes_json  73096 non-null  object 
 18  date               73096 non-null  object 
 19  weekday            73096 non-null  object 
 20  start_time         73096 non-null  object 
 21  end_time           73096 non-null  object 
dtypes: float64(8), int64(2), object(12)
memory usage: 12.8+ MB

Preis nach Ort und Zeit¶

Postleitzahl vs. Wochentag vs. Preis¶

In [5]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
df['weekday'] = pd.Categorical(df['weekday'], categories=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], ordered=True)
df['weekday'] = pd.Categorical(df['weekday'], ordered=True)

plz_weekday = df.groupby(['post_code', 'weekday'], observed=False)['e5'].mean().reset_index()
plt.figure(figsize=(10, 5))
sns.lineplot(data=plz_weekday, x='weekday', y='e5', hue='post_code', marker='o')

plt.title('Durchschnittlicher E5-Preis nach Postleitzahl und Wochentag')
plt.xlabel('Wochentag')
plt.ylabel('E5-Preis')
plt.xticks(rotation=45)
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='Postleitzahl', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Die Preise steigen zum Ende der Woche, mit dem höchsten Wert am Sonntag.
  • Der geringste Wert ist am Dienstag.
  • Es gibt Unterschiede bei den unterschiedlichen Postleitzahlen:
    • 32425 hat die niedrigsten E5 Preise, nahe 32423.
    • Mit etwas Abstand sind die E5 Preise von 32429 höher und am höchsten von 32427.
In [6]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
df['weekday'] = pd.Categorical(df['weekday'], categories=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], ordered=True)
df['weekday'] = pd.Categorical(df['weekday'], ordered=True)

plz_weekday = df.groupby(['post_code', 'weekday'], observed=False)['e10'].mean().reset_index()
plt.figure(figsize=(10, 5))
sns.lineplot(data=plz_weekday, x='weekday', y='e10', hue='post_code', marker='o')

plt.title('Durchschnittlicher E10-Preis nach Postleitzahl und Wochentag')
plt.xlabel('Wochentag')
plt.ylabel('E10-Preis')
plt.xticks(rotation=45)
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='Postleitzahl', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Die Postleitzahlen 32423 und 32425 sind hier sehr ähnlich und nahe beieinander.
  • 32429 liegt zwischen den 32427 und den unteren beiden Postleitzahlen.
In [7]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
df['weekday'] = pd.Categorical(df['weekday'], categories=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], ordered=True)
df['weekday'] = pd.Categorical(df['weekday'], ordered=True)

plz_weekday = df.groupby(['post_code', 'weekday'], observed=False)['diesel'].mean().reset_index()
plt.figure(figsize=(10, 5))
sns.lineplot(data=plz_weekday, x='weekday', y='diesel', hue='post_code', marker='o')
plt.title('Durchschnittlicher Diesel-Preis nach Postleitzahl und Wochentag')
plt.xlabel('Wochentag')
plt.ylabel('Diesel-Preis')
plt.xticks(rotation=45)
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='Postleitzahl', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • 32427 ist am teursten und hat einen größeren Abstand zu den anderen Postleitzahlen.
  • Der Preisanstieg bei 32429 ist von Freitag auf Samstag stärker, als bei den anderen Postleitzahlen.

Postleitzahl vs. Stunde vs. Preis¶

In [8]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['post_code', 'hour'], observed=False)['e5'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='e5', hue='post_code', marker='o', errorbar=None)
plt.title('E5-Preis nach Stunde und Postleitzahl')
plt.xlabel('Stunde')
plt.ylabel('E5-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID')
plt.tight_layout()
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/3395774060.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Am frühen Morgen und am späten Abend sind die Preise bei den unterschiedlichen Postleitzahlen stärker auseinander.
    • Dies kann an den unterschiedlichen Öffnungszeiten der Tankstellen liegen
  • Tagsüber gleichen sich die Verläufe der Preise aneinander an.
    • Am Morgen sind die Preise am höchsten und werden dann geringer.
    • Um 9 Uhr erreichen sie einen lokalen Tiefpunkt und steigen dann leicht, um dann gegen 11 Uhr wieder zu fallen.
    • Am Abend steigen die Preise und haben um 21 Uhr einen lokalen Hochpunkt.
    • Um 20 Uhr hat die Postleitzahl 32423 einen stärkeren Tiefpunkt als die anderen Postleitzahlen, um dann um 21 Uhr stark zu steigen und wieder auf das Niveau der anderen Tankstellen zu kommen.
In [9]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['post_code', 'hour'], observed=False)['e10'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='e10', hue='post_code', marker='o', errorbar=None)
plt.title('E10-Preis nach Stunde und Postleitzahl')
plt.xlabel('Stunde')
plt.ylabel('E10-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID')
plt.tight_layout()
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/795386459.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • gleiche Beobachtungen, wie bei den E5-Preisen.
In [10]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['post_code', 'hour'], observed=False)['diesel'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='diesel', hue='post_code', marker='o', errorbar=None)
plt.title('Diesel-Preis nach Stunde und Postleitzahl')
plt.xlabel('Stunde')
plt.ylabel('Diesel-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID')
plt.tight_layout()
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/1605611753.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Auch hier sind die Verläufe der Tankpreise von den unterschiedlichen Postleitzahlen sehr ähnlich zueinander.
  • Unabhängig von der Postleitzahl ist der niedrigste Preis zwischen 18 und 19 Uhr.
  • Ab ca. 20 Uhr steigen die Preise rapide an, besonders gegen 22–23 Uhr.
  • 32427 scheint durchgehend leicht über den anderen zu liegen.
  • Die Preise schwanken zwischen ca. 1.60€ und 1.71€, also um mehr als 10 Cent pro Liter im Tagesverlauf.

Postleitzahl vs. Datum vs. Preis¶

In [11]:
# Quellen: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.gca.html, https://seaborn.pydata.org/generated/seaborn.lineplot.html
date_prices = df.groupby(['post_code', 'date'], observed=False)['e5'].mean().reset_index()
date_prices["date"] = pd.to_datetime(date_prices["date"]).dt.date

plt.figure(figsize=(12, 5))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Alle Monate markieren
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
sns.lineplot(data=date_prices, x='date', y='e5', hue='post_code', errorbar=None)
plt.title('E5-Preis nach Datum und Postleitzahl')
plt.xlabel('Stunde')
plt.ylabel('E5-Preis')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Die Preise steigen von Januar bis Mai, mit einem Höhepunkt im späten April / frühen Mai. Über 1,90€.
  • Ab Mai/Juni beginnt ein klarer Preisrückgang, der bis September anhält.
  • Der niedrigste Preis liegt etwa zwischen September und Oktober mit ca. 1,65–1,70€.
  • Im November und Dezember steigen die Preise wieder leicht an.
  • Die Preisverläufe in den PLZ-Bereichen 32423, 32425, 32427, 32429 sind nahezu gleich.
    • Kleine Unterschiede im Preisniveau
In [12]:
# Quellen: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.gca.html, https://seaborn.pydata.org/generated/seaborn.lineplot.html
date_prices = df.groupby(['post_code', 'date'], observed=False)['e10'].mean().reset_index()
date_prices["date"] = pd.to_datetime(date_prices["date"]).dt.date

plt.figure(figsize=(12, 5))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Alle Monate markieren
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
sns.lineplot(data=date_prices, x='date', y='e10', hue='post_code', errorbar=None)
plt.title('E10-Preis nach Datum und Postleitzahl')
plt.xlabel('Stunde')
plt.ylabel('E10-Preis')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Auch hier ein Anstieg zwischen Januar bis April
  • Ab Mai sinken die Preise kontinuierlich, bis sie im Herbst auf unter 1,60€ fallen.
  • Wieder ein leichter Preisanstieg ab November/Dezember, analog zu E5.
  • Die Postleitzahlen zeigen auch hier einen nahezu gleichen Verlauf auf leicht unterschiedlichen Preisniveaus.
In [13]:
# Quellen: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.gca.html, https://seaborn.pydata.org/generated/seaborn.lineplot.html
date_prices = df.groupby(['post_code', 'date'], observed=False)['diesel'].mean().reset_index()
date_prices["date"] = pd.to_datetime(date_prices["date"]).dt.date

plt.figure(figsize=(12, 5))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Alle Monate markieren
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
sns.lineplot(data=date_prices, x='date', y='diesel', hue='post_code', errorbar=None)
plt.title('Diesel-Preis nach Datum und Postleitzahl')
plt.xlabel('Stunde')
plt.ylabel('Diesel-Preis')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Anders als bei E5/E10 fällt der Peak nicht im April, sondern zwischen Mai und Juli.
  • Auch Diesel fällt im späten Sommer und Herbst deutlich
  • Wieder ähnlich zu E5/E10 ein Anstieg, aber etwas flacher.
  • Auch hier verlaufen die Linien der Posteleitzahlen nahezu identisch.

Preis nach Anbieter Ort und Zeit (check)¶

ID vs. Stunde vs. Preis¶

In [14]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['station_uuid', 'hour'], observed=False)['e5'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='e5', hue='station_uuid', marker='o', errorbar=None)
plt.title('E5-Preis nach Stunde und ID')
plt.xlabel('Stunde')
plt.ylabel('E5-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/1980620333.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Der E5-Preis sinkt im Tagesverlauf typischerweise bis zum Nachmittag (gegen 14–15 Uhr) und steigt dann wieder an.
  • Gegen 23 Uhr ist ein starker Preisanstieg sichtbar.
  • Die Preise bewegen sich in einem engen Korridor (zwischen ca. 1,75 und 1,87 €), einzelne Ausreißer zeigen sich in den frühen Morgen- oder Abendstunden.
  • Die meisten Kurven der Tankstellen überlagern sich stark. Die Tankstelle 'e35...' ist jedoch zu den meisten Zeitpunkten teurer, als die anderen Tankstellen.
In [15]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['station_uuid', 'hour'], observed=False)['e10'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='e10', hue='station_uuid', marker='o', errorbar=None)
plt.title('E10-Preis nach Stunde und ID')
plt.xlabel('Stunde')
plt.ylabel('E10-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.tight_layout()
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/3206259464.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Ähnlich zu E5, die Preise sinken tagsüber und steigen am Abend wieder deutlich.
  • Zwischen 4 und 19 Uhr gibt es ein relativ stabiles Preisniveau, danach steigen die Werte deutlich.
  • Etwas weniger stark ausgeprägte Unterschiede als bei E5, die Linien verlaufen gleichmäßiger.
  • Wieder sehr hohe Ausschläge gegen 23 Uhr bei einzelnen Tankstellen.
  • Auch hier ist die Tankstelle 'e35...' zu den meisten Zeitpunkten am teuersten.
In [16]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['station_uuid', 'hour'], observed=False)['diesel'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='diesel', hue='station_uuid', marker='o', errorbar=None)
plt.title('Diesel-Preis nach Stunde und ID')
plt.xlabel('Stunde')
plt.ylabel('Diesel-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/1662548682.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Preise am frühen Morgen (ca. 3 bis 5 Uhr) besonders niedrig, anschließend langsamer Anstieg bis zum Abend.
  • Preisunterschiede zwischen den Tankstellen sind sichtbar, aber ebenfalls relativ gering.
  • Ab ca. 20 Uhr steigen die Preise deutlich bei fast allen Tankstellen.

ID, Wochentag, Preis¶

In [17]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
mean_weekday_brand = df.groupby(['station_uuid', 'weekday'], observed=False)['e5'].mean().reset_index()

plt.figure(figsize=(12, 5))
sns.lineplot(data=mean_weekday_brand, x='weekday', y='e5', hue='station_uuid', marker='o', errorbar=None)
plt.title('E5-Preis nach Wochentag und ID')
plt.xlabel('Wochentag')
plt.ylabel('E5-Preis')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Die meisten Tankstellen weisen unter der Woche (Montag bis Samstag) relativ stabile E5-Preise auf.
  • Am Sonntag steigen die Preise bei fast allen IDs deutlich an. Dies könnte auf ein typisches Wochenendverhalten zurückzuführen sein.
  • Einzelne Ausreißer (z.B. die blaue Linie unten) zeigen deutlich niedrigere Preise an bestimmten Tagen, was auf fehlerhafte Daten hindeuten könnte.
  • Unterschiede zwischen Tankstellen sind insgesamt sichtbar, aber nicht extrem stark.
In [18]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
mean_weekday_brand = df.groupby(['station_uuid', 'weekday'], observed=False)['e10'].mean().reset_index()

plt.figure(figsize=(12, 5))
sns.lineplot(data=mean_weekday_brand, x='weekday', y='e10', hue='station_uuid', marker='o', errorbar=None)
plt.title('E10-Preis nach Wochentag und ID')
plt.xlabel('Wochentag')
plt.ylabel('E10-Preis')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Konstante Preise von Montag bis Samstag.
  • Deutlicher Anstieg am Sonntag bei fast allen Tankstellen.
  • Die Preisspanne zwischen den IDs ist etwas kleiner als die Preisspanne bei E5.
  • Auch hier gibt es eine ID mit ungewöhnlich niedrigen Preisen unter der Woche (dunkelblaue Linie)
In [19]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
mean_weekday_brand = df.groupby(['station_uuid', 'weekday'], observed=False)['diesel'].mean().reset_index()

plt.figure(figsize=(12, 5))
sns.lineplot(data=mean_weekday_brand, x='weekday', y='diesel', hue='station_uuid', marker='o', errorbar=None)
plt.title('Diesel-Preis nach Wochentag und ID')
plt.xlabel('Wochentag')
plt.ylabel('Diesel-Preis')
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='ID', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Dieselpreise zeigen konstante bis leicht sinkende Preise unter der Woche, dann starker Anstieg am Sonntag.
  • Der Unterschied zwischen Wochentagen ist hier teilweise etwas stärker ausgeprägt als bei E5/E10.
  • Es gibt eine auffällige ID mit sehr hohem Preis am Montag und Sonntag, während der Preis unter der Woche deutlich sinkt.
  • Die Clusterbildung der Linien ist besonders bei Diesel klar sichtbar. Das deutet auf Gruppen von Tankstellen mit sehr ähnlichem Preisniveau und Verhalten hin.

Brand, Stunde, Preis¶

In [20]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['brand', 'hour'], observed=False)['e5'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='e5', hue='brand', marker='o', errorbar=None)
plt.title('E5-Preis nach Stunde und Marke')
plt.xlabel('Stunde')
plt.ylabel('E5-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='Marke', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/1865313845.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Die Linien zeigen die durchschnittlichen E5-Preise pro Stunde, gruppiert nach Tankstellenmarke.
  • Leichter Rückgang tagsüber und Anstieg am Abend.
  • Calpam zeigt ungewöhnlich niedrige Preise zwischen 0 und 3 Uhr und einen plötzlichen Anstieg ab 4 Uhr. Dies deutet auf fehlerhafte Messwerte hin.
In [21]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['brand', 'hour'], observed=False)['e10'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='e10', hue='brand', marker='o', errorbar=None)
plt.title('E10-Preis nach Stunde und Marke')
plt.xlabel('Stunde')
plt.ylabel('E10-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='Marke', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/3980592656.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Die E10-Preise zeigen ein ähnliches Muster wie E5, mit tageszeitlicher Abnahme.
  • Marken wie ARAL, Shell, Westfalen liegen im oberen Preisbereich.
  • Wieder fällt Calpam durch extrem niedrige Preise nachts auf
In [22]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.lineplot.html
hourly_prices = df.groupby(['brand', 'hour'], observed=False)['diesel'].mean().reset_index()
hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour

plt.figure(figsize=(12, 5))
sns.lineplot(data=hourly_prices, x='hour', y='diesel', hue='brand', marker='o', errorbar=None)
plt.title('Diesel-Preis nach Stunde und Marke')
plt.xlabel('Stunde')
plt.ylabel('Diesel-Preis')
plt.xticks(range(0, 24))
plt.grid(True, linestyle='--', alpha=0.6)
plt.legend(title='Marke', bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0.)
plt.show()
/var/folders/_9/fyqnr96j0q7_tlytmj22wy8c0000gn/T/ipykernel_83097/3523434088.py:3: UserWarning: Could not infer format, so each element will be parsed individually, falling back to `dateutil`. To ensure parsing is consistent and as-expected, please specify a format.
  hourly_prices["hour"] = pd.to_datetime(hourly_prices["hour"]).dt.hour
No description has been provided for this image

Auffälligkeiten:

  • Nachts vor allem stabile Preise, ein Minimum am Nachmittag und steigende Preise ab ca. 20 Uhr.
  • Auch hier ist Calpam ein Ausreißer mit unrealistisch tiefen Werten nachts.
  • Westfalen, ARAL, Shell sind im oberen Preisbereich konstant.

Öffnungszeiten im Kontext von Wochentag & Preis¶

Wochentag, Öffnungzeit, Preis¶

Auffälligkeiten:¶

In [23]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
df['weekday'] = pd.Categorical(df['weekday'], categories=weekday_order, ordered=True)
heatmap_data = df.groupby(['weekday', 'start_time'], observed=False)['e5'].mean().unstack()

plt.figure(figsize=(4, 3))
sns.heatmap(heatmap_data, cmap='YlGnBu')
plt.title("Durchschnittlicher E5-Preis nach Öffnungszeit und Wochentag")
plt.xlabel("Startstunde")
plt.ylabel("Wochentag")
plt.xticks(rotation=90)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Tankstellen mit früher Öffnungszeit (5 bis 7 Uhr) zeigen tendenziell höhere E5-Preise (speziell an Dienstagen und Donnerstagen).
  • Tankstellen, die 24 Studen geöffnet haben, haben einen teureren Durchschnittspreis.
In [24]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
df['weekday'] = pd.Categorical(df['weekday'], categories=weekday_order, ordered=True)
heatmap_data = df.groupby(['weekday', 'start_time'], observed=False)['e10'].mean().unstack()

plt.figure(figsize=(4, 3))
sns.heatmap(heatmap_data, cmap='YlGnBu')
plt.title("Durchschnittlicher E10-Preis nach Öffnungszeit und Wochentag")
plt.xlabel("Startstunde")
plt.ylabel("Wochentag")
plt.xticks(rotation=90)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Tankstellen, die rund um die Uhr geöffnet haben, sind tendenziell teurer (ausgenommen Sonntag).
In [25]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
df['weekday'] = pd.Categorical(df['weekday'], categories=weekday_order, ordered=True)
heatmap_data = df.groupby(['weekday', 'start_time'], observed=False)['diesel'].mean().unstack()

plt.figure(figsize=(4, 3))
sns.heatmap(heatmap_data, cmap='YlGnBu')
plt.title("Durchschnittlicher Diesel-Preis nach Öffnungszeit und Wochentag")
plt.xlabel("Startstunde")
plt.ylabel("Wochentag")
plt.xticks(rotation=90)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Tankstellen, die früh öffnen sind teurer, besonders Dienstag bis Donnerstag.

Wochentag, Schließzeit, Preis¶

In [26]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
df['weekday'] = pd.Categorical(df['weekday'], categories=weekday_order, ordered=True)
heatmap_data = df.groupby(['weekday', 'end_time'], observed=False)['e5'].mean().unstack()

plt.figure(figsize=(4, 3))
sns.heatmap(heatmap_data, cmap='YlGnBu')
plt.title("Durchschnittlicher E5-Preis nach Schließzeit und Wochentag")
plt.xlabel("Endstunde")
plt.ylabel("Wochentag")
plt.xticks(rotation=90)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Eine Tankstelle die früher schließt, hat einen tendenziell geringeren Preis.
  • Tankstellen, die rund um die Uhr geöffnet sind, haben einen höheren Preis.
In [27]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
df['weekday'] = pd.Categorical(df['weekday'], categories=weekday_order, ordered=True)
heatmap_data = df.groupby(['weekday', 'end_time'], observed=False)['e10'].mean().unstack()

plt.figure(figsize=(4, 3))
sns.heatmap(heatmap_data, cmap='YlGnBu')
plt.title("Durchschnittlicher E10-Preis nach Schließzeit und Wochentag")
plt.xlabel("Endstunde")
plt.ylabel("Wochentag")
plt.xticks(rotation=90)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Tankstellen die früher schließen haben günstigere Preise.
  • 24 / 7 Tankstellen haben erhöhte Preise.
In [28]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
df['weekday'] = pd.Categorical(df['weekday'], categories=weekday_order, ordered=True)
heatmap_data = df.groupby(['weekday', 'end_time'], observed=False)['diesel'].mean().unstack()

plt.figure(figsize=(4, 3))
sns.heatmap(heatmap_data, cmap='YlGnBu')
plt.title("Durchschnittlicher Diesel-Preis nach Schließzeit und Wochentag")
plt.xlabel("Endstunde")
plt.ylabel("Wochentag")
plt.xticks(rotation=90)
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Ähnliche Strukturen wie die anderen Kraftstoffe.

Preis + Änderung + Zeitpunkt¶

Preis, Preischange und Stunde¶

In [29]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
df['price_bin'] = pd.cut(df['e5'], bins=50)
heatmap_data = df.groupby(['hour', 'price_bin'], observed=False)['e5change'].mean().unstack()

plt.figure(figsize=(10, 5))
sns.heatmap(heatmap_data, cmap='RdBu_r', center=0)
plt.title('Durchschnittliche Preisänderung nach Stunde und Preisniveau')
plt.xlabel('E5-Preisbereich')
plt.ylabel('Stunde')
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Die Preisänderungen finden fast durchgehend über den gesamten Tagesverlauf statt. Zwischen 05:00 und 22:00 Uhr ist besonders viel Aktivität sichtbar.
  • Einzelne Zellen mit Werten nahe 2 treten sporadisch in niedrigen und mittleren Preisbereichen auf, insbesondere gegen 22 Uhr.
  • In der Nacht (00:00 bis 04:00 Uhr) sind wenige Änderungen.
  • Preisänderungen scheinen sich über fast alle Preisniveaus zu verteilen, allerdings sind in sehr hohen Preisbereichen (ab ca. 1.93 €) die Änderungen weniger häufig.
In [30]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
df['price_bin'] = pd.cut(df['e10'], bins=50)
heatmap_data = df.groupby(['hour', 'price_bin'], observed=False)['e10change'].mean().unstack()

plt.figure(figsize=(10, 5))
sns.heatmap(heatmap_data, cmap='RdBu_r', center=0)
plt.title('Durchschnittliche Preisänderung nach Stunde und Preisniveau')
plt.xlabel('E10-Preisbereich')
plt.ylabel('Stunde')
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Auch hier sind die meisten Preisänderungen im Bereich von 05:00 bis 22:00 Uhr sichtbar. Der Tagesverlauf ähnelt dem von E5 deutlich.
  • Zwischen 22:00 und 23:00 Uhr gibt es ebenfalls eine deutliche Preisänderung in einem niedrigen Preisbereich.
  • Die Intensität der Änderungen wirkt minimal schwächer als bei E5, wobei die Farbverteilung vergleichbar ist.
In [31]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
df['price_bin'] = pd.cut(df['diesel'], bins=50)
heatmap_data = df.groupby(['hour', 'price_bin'], observed=False)['dieselchange'].mean().unstack()

plt.figure(figsize=(10, 5))
sns.heatmap(heatmap_data, cmap='RdBu_r', center=0)
plt.title('Durchschnittliche Preisänderung nach Stunde und Preisniveau')
plt.xlabel('Diesel-Preisbereich')
plt.ylabel('Stunde')
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Die meiste Aktivität zeigt sich zwischen 06:00 bis 20:00 Uhr.
  • Die Aktivität konzentriert sich tendenziell stärker auf die niedrigen bis mittleren Preisbereiche.
  • Diesel zeigt eine dichtere Belegung des gesamten Plots mit Preisänderungen, was auf häufigere oder regelmäßigere Änderungen hindeutet.
  • Achtung, andere Skala

Preis, Preischange und wochentag¶

In [32]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
df['price_bin'] = pd.cut(df['e5'], bins=50)
heatmap_data = df.groupby(['weekday', 'price_bin'], observed=False)['e5change'].mean().unstack()

plt.figure(figsize=(10, 5))
sns.heatmap(heatmap_data, cmap='RdBu_r', center=0)
plt.title('Durchschnittliche Preisänderung nach Wochentag und Preisniveau')
plt.xlabel('E5-Preisbereich')
plt.ylabel('Wochentag')
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Samstags ist ein niedriges Preisniveau mit der höchsten durchschnittlichen Preisänderungen (dunkelpink).
  • Donnerstags weist bei bestimmten Preisbereichen (um 1.87 bis 1.90) einen auffällig niedrigen Wert (dunkelblau/schwarz) auf, möglicherweise stabile Preise oder wenige Änderungen.
  • Insgesamt moderate Schwankungen über alle Tage.
In [33]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
df['price_bin'] = pd.cut(df['e10'], bins=50)
heatmap_data = df.groupby(['weekday', 'price_bin'], observed=False)['e10change'].mean().unstack()

plt.figure(figsize=(10, 5))
sns.heatmap(heatmap_data, cmap='RdBu_r', center=0)
plt.title('Durchschnittliche Preisänderung nach Wochentag und Preisniveau')
plt.xlabel('E10-Preisbereich')
plt.ylabel('Wochentag')
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Donnerstag ebenfalls mit einem auffälligen dunklen Bereich bei hohen Preisniveau.
  • Montag bis Mittwoch relativ gleich.
In [34]:
# Quelle: https://seaborn.pydata.org/generated/seaborn.heatmap.html
df['price_bin'] = pd.cut(df['diesel'], bins=50)
heatmap_data = df.groupby(['weekday', 'price_bin'], observed=False)['dieselchange'].mean().unstack()

plt.figure(figsize=(10, 5))
sns.heatmap(heatmap_data, cmap='RdBu_r', center=0)
plt.title('Durchschnittliche Preisänderung nach Wochentag und Preisniveau')
plt.xlabel('Diesel-Preisbereich')
plt.ylabel('Wochentag')
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Keine starken Ausschläge, es könnte auf konstant kleine Preisänderungen hindeuten.
  • Dienstag zeigt bei höherem Preisniveau teilweise etwas höhere Änderungen.

Preis, Preischange und Datum¶

In [35]:
# Quellen: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.gca.html, https://seaborn.pydata.org/generated/seaborn.lineplot.html
df['price_level'] = pd.cut(df['e5'], bins=[1.3, 1.5, 1.7, 1.9], labels=['niedrig', 'mittel', 'hoch'])
hourly_change = df.groupby(['date', 'price_level'], observed=False)['e5change'].mean().reset_index()
hourly_change["date"] = pd.to_datetime(hourly_change["date"]).dt.date

plt.figure(figsize=(10, 5))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Alle Monate markieren
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
sns.lineplot(data=hourly_change, x='date', y='e5change', hue='price_level', marker='.')
plt.title('Preisänderung nach Datum und Preisniveau E5')
plt.xlabel('Datum')
plt.ylabel('Durchschnittliche Preisänderung')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Mittel-Preisniveau zeigt im Januar/Februar eine extreme Spitze bis zu einem Wert von 2.0, was auf eine sehr hohe Preisänderung an einzelnen Tagen hindeutet.
  • Im weiteren Verlauf des Jahres bleiben die Unterschiede zwischen niedrig, mittel und hoch relativ gering
In [36]:
# Quellen: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.gca.html, https://seaborn.pydata.org/generated/seaborn.lineplot.html
df['price_level'] = pd.cut(df['e10'], bins=[1.3, 1.5, 1.7, 1.9], labels=['niedrig', 'mittel', 'hoch'])
hourly_change = df.groupby(['date', 'price_level'], observed=False)['e10change'].mean().reset_index()
hourly_change["date"] = pd.to_datetime(hourly_change["date"]).dt.date

plt.figure(figsize=(10, 5))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Alle Monate markieren
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
sns.lineplot(data=hourly_change, x='date', y='e10change', hue='price_level', marker='.')
plt.title('Preisänderung nach Datum und Preisniveau E10')
plt.xlabel('Datum')
plt.ylabel('Durchschnittliche Preisänderung')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Deutlich mehr Schwankungen bei Mittel im ersten Halbjahr (v. a. März/April), mit Werten bis runter zu 0.3, was auf starke Preisrückgänge hindeutet.
  • Einzelne Spitzen nach oben bei Hoch im Oktober (1.5).
  • Niedrig nicht vorhanden.
In [37]:
# Quellen: https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.gca.html, https://seaborn.pydata.org/generated/seaborn.lineplot.html
df['price_level'] = pd.cut(df['diesel'], bins=[1.6, 1.7, 1.8, 1.9], labels=['niedrig', 'mittel', 'hoch'])
hourly_change = df.groupby(['date', 'price_level'], observed=False)['dieselchange'].mean().reset_index()
hourly_change["date"] = pd.to_datetime(hourly_change["date"]).dt.date

plt.figure(figsize=(10, 5))
plt.gca().xaxis.set_major_locator(mdates.MonthLocator(interval=1)) # Alle Monate markieren
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b'))
sns.lineplot(data=hourly_change, x='date', y='dieselchange', hue='price_level', marker='.')

plt.title('Preisänderung nach Datum und Preisniveau Diesel')
plt.xlabel('Datum')
plt.ylabel('Durchschnittliche Preisänderung')
plt.tight_layout()
plt.show()
No description has been provided for this image

Auffälligkeiten:

  • Niedrig schwankt deutlich stärker als die anderen Preisniveaus, insbesondere im Zeitraum Februar bis April und erneut im Herbst.
  • Mittel verläuft fast konstant auf dem Niveau von 1.0, mit minimalen Abweichungen.
  • Hoch ist relativ stabil, mit gelegentlichen Spitzen.
In [ ]: